home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / dev / misc / AmigaSDLsrc.lha / amisrc / SDL_audio.c < prev    next >
C/C++ Source or Header  |  2001-04-29  |  14KB  |  600 lines

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     slouken@devolution.com
  21. */
  22.  
  23. #ifdef SAVE_RCSID
  24. static char rcsid =
  25.  "@(#) $Id: SDL_audio.c,v 1.7.2.42 2001/03/21 17:19:56 hercules Exp $";
  26. #endif
  27.  
  28. /* Allow access to a raw mixing buffer */
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32.  
  33. #include "SDL.h"
  34. #include "SDL_audio.h"
  35. #include "SDL_timer.h"
  36. #include "SDL_error.h"
  37. #include "SDL_audio_c.h"
  38. #include "SDL_audiomem.h"
  39. #include "SDL_sysaudio.h"
  40.  
  41. /* Available audio drivers */
  42. static AudioBootStrap *bootstrap[] = {
  43. #if defined(unix) && \
  44.    !defined(linux) && !defined(__FreeBSD__) && !defined(__CYGWIN32__) \
  45.    && !defined(__bsdi__)
  46.     &AUDIO_bootstrap,
  47. #endif
  48. #ifdef OSS_SUPPORT
  49.     &DSP_bootstrap,
  50.     &DMA_bootstrap,
  51. #endif
  52. #ifdef ALSA_SUPPORT
  53.     &ALSA_bootstrap,
  54. #endif
  55. #ifdef ARTSC_SUPPORT
  56.     &ARTSC_bootstrap,
  57. #endif
  58. #ifdef ESD_SUPPORT
  59.     &ESD_bootstrap,
  60. #endif
  61. #ifdef NAS_SUPPORT
  62.     &NAS_bootstrap,
  63. #endif
  64. #ifdef ENABLE_DIRECTX
  65.     &DSOUND_bootstrap,
  66. #endif
  67. #ifdef ENABLE_WINDIB
  68.     &WAVEOUT_bootstrap,
  69. #endif
  70. #ifdef __BEOS__
  71.     &BAUDIO_bootstrap,
  72. #endif
  73. #if defined(macintosh) || TARGET_API_MAC_CARBON
  74.     &SNDMGR_bootstrap,
  75. #endif
  76. #ifdef _AIX
  77.     &Paud_bootstrap,
  78. #endif
  79. #ifdef ENABLE_AHI
  80.     &AHI_bootstrap,
  81. #endif
  82.  
  83.     NULL
  84. };
  85. SDL_AudioDevice *current_audio = NULL;
  86.  
  87. /* Various local functions */
  88. int SDL_AudioInit(const char *driver_name);
  89. void SDL_AudioQuit(void);
  90.  
  91. #ifdef ENABLE_AHI
  92. static int audio_configured=0;
  93. #endif
  94.  
  95. /* The general mixing thread function */
  96. int SDL_RunAudio(void *audiop)
  97. {
  98.     SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
  99.     Uint8 *stream;
  100.     int    stream_len;
  101.     void  *udata;
  102.     void (*fill)(void *userdata,Uint8 *stream, int len);
  103.     int    silence;
  104. #ifdef ENABLE_AHI
  105.     int started=0;
  106.  
  107. /* AmigaOS NEEDS that the audio driver is opened in the thread that uses it! */
  108.  
  109.     D(bug("Task audio started audio struct:<%lx>...\n",audiop));
  110.  
  111.     D(bug("Before Openaudio..."));
  112.     if(audio->OpenAudio(audio, &audio->spec)==-1)
  113.     {
  114.         D(bug("Open audio failed...\n"));
  115.         return(-1);
  116.     }
  117.     D(bug("OpenAudio...OK\n"));
  118. #endif
  119.  
  120.     /* Perform any thread setup */
  121.     if ( audio->ThreadInit ) {
  122.         audio->ThreadInit(audio);
  123.     }
  124.     audio->threadid = SDL_ThreadID();
  125.  
  126.     /* Set up the mixing function */
  127.     fill  = audio->spec.callback;
  128.     udata = audio->spec.userdata;
  129.  
  130.     audio_configured=1;
  131.  
  132. #ifdef ENABLE_AHI
  133.     D(bug("Audio configured... Checking for conversion\n"));
  134.     SDL_mutexP(audio->mixer_lock);
  135.     D(bug("Semaphore obtained...\n"));
  136. #endif
  137.  
  138.     if ( audio->convert.needed ) {
  139.         if ( audio->convert.src_format == AUDIO_U8 ) {
  140.             silence = 0x80;
  141.         } else {
  142.             silence = 0;
  143.         }
  144.         stream_len = audio->convert.len;
  145.     } else {
  146.         silence = audio->spec.silence;
  147.         stream_len = audio->spec.size;
  148.     }
  149.     stream = audio->fake_stream;
  150.  
  151. #ifdef ENABLE_AHI
  152.     SDL_mutexV(audio->mixer_lock);
  153.     D(bug("Entering audio loop...\n"));
  154. #endif
  155.  
  156.  
  157.     /* Loop, filling the audio buffers */
  158.     while ( audio->enabled ) {
  159.  
  160.         /* Wait for new current buffer to finish playing */
  161.         if ( stream == audio->fake_stream ) {
  162.             SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
  163.         } else {
  164. #ifdef ENABLE_AHI
  165.             if(started>1)
  166. #endif
  167.             audio->WaitAudio(audio);
  168.         }
  169.  
  170.         /* Fill the current buffer with sound */
  171.         if ( audio->convert.needed ) {
  172.             if ( audio->convert.buf ) {
  173.                 stream = audio->convert.buf;
  174.             } else {
  175.                 continue;
  176.             }
  177.         } else {
  178.             stream = audio->GetAudioBuf(audio);
  179.             if ( stream == NULL ) {
  180.                 stream = audio->fake_stream;
  181.             }
  182.         }
  183.         memset(stream, silence, stream_len);
  184.  
  185.         if ( ! audio->paused ) {
  186.             SDL_mutexP(audio->mixer_lock);
  187.             (*fill)(udata, stream, stream_len);
  188.             SDL_mutexV(audio->mixer_lock);
  189.         }
  190.  
  191.         /* Convert the audio if necessary */
  192.         if ( audio->convert.needed ) {
  193.             SDL_ConvertAudio(&audio->convert);
  194.             stream = audio->GetAudioBuf(audio);
  195.             if ( stream == NULL ) {
  196.                 stream = audio->fake_stream;
  197.             }
  198.             memcpy(stream, audio->convert.buf,
  199.                            audio->convert.len_cvt);
  200.         }
  201.  
  202.         /* Ready current buffer for play and change current buffer */
  203.         if ( stream != audio->fake_stream ) {
  204.             audio->PlayAudio(audio);
  205. #ifdef ENABLE_AHI
  206. /* AmigaOS don't have to wait the first time audio is played! */
  207.             started++;
  208. #endif
  209.         }
  210.     }
  211.     /* Wait for the audio to drain.. */
  212.     if ( audio->WaitDone ) {
  213.         audio->WaitDone(audio);
  214.     }
  215.  
  216. #ifdef ENABLE_AHI
  217.     D(bug("WaitAudio...Done\n"));
  218.  
  219.     audio->CloseAudio(audio);
  220.  
  221.     D(bug("CloseAudio..Done, subtask exiting...\n"));
  222.     audio_configured=0;
  223. #endif
  224.     return(0);
  225. }
  226.  
  227. int SDL_AudioInit(const char *driver_name)
  228. {
  229.     SDL_AudioDevice *audio;
  230.     int i = 0, idx;
  231.  
  232.     /* Check to make sure we don't overwrite 'current_audio' */
  233.     if ( current_audio != NULL ) {
  234.         SDL_AudioQuit();
  235.     }
  236.  
  237.     /* Select the proper audio driver */
  238.     audio = NULL;
  239.     idx = 0;
  240. #ifdef unix
  241.     if ( (driver_name == NULL) && (getenv("ESPEAKER") != NULL) ) {
  242.         /* Ahem, we know that if ESPEAKER is set, user probably wants
  243.            to use ESD, but don't start it if it's not already running.
  244.            This probably isn't the place to do this, but... Shh! :)
  245.          */
  246.         for ( i=0; bootstrap[i]; ++i ) {
  247.             if ( strcmp(bootstrap[i]->name, "esd") == 0 ) {
  248.                 const char *esd_no_spawn;
  249.  
  250.                 /* Don't start ESD if it's not running */
  251.                 esd_no_spawn = getenv("ESD_NO_SPAWN");
  252.                 if ( esd_no_spawn == NULL ) {
  253.                     putenv("ESD_NO_SPAWN=1");
  254.                 }
  255.                 if ( bootstrap[i]->available() ) {
  256.                     audio = bootstrap[i]->create(0);
  257.                     break;
  258.                 }
  259. #ifdef linux    /* No unsetenv() on most platforms */
  260.                 if ( esd_no_spawn == NULL ) {
  261.                     unsetenv("ESD_NO_SPAWN");
  262.                 }
  263. #endif
  264.             }
  265.         }
  266.     }
  267. #endif /* unix */
  268.     if ( audio == NULL ) {
  269.         if ( driver_name != NULL ) {
  270. #if 0    /* This will be replaced with a better driver selection API */
  271.             if ( strrchr(driver_name, ':') != NULL ) {
  272.                 idx = atoi(strrchr(driver_name, ':')+1);
  273.             }
  274. #endif
  275.             for ( i=0; bootstrap[i]; ++i ) {
  276.                 if (strncmp(bootstrap[i]->name, driver_name,
  277.                             strlen(bootstrap[i]->name)) == 0) {
  278.                     if ( bootstrap[i]->available() ) {
  279.                         audio=bootstrap[i]->create(idx);
  280.                         break;
  281.                     }
  282.                 }
  283.             }
  284.         } else {
  285.             for ( i=0; bootstrap[i]; ++i ) {
  286.                 if ( bootstrap[i]->available() ) {
  287.                     audio = bootstrap[i]->create(idx);
  288.                     if ( audio != NULL ) {
  289.                         break;
  290.                     }
  291.                 }
  292.             }
  293.         }
  294.         if ( audio == NULL ) {
  295.             SDL_SetError("No available audio device");
  296. #if 0 /* Don't fail SDL_Init() if audio isn't available.
  297.          SDL_OpenAudio() will handle it at that point.  *sigh*
  298.        */
  299.             return(-1);
  300. #endif
  301.         }
  302.     }
  303.     current_audio = audio;
  304.     if ( current_audio ) {
  305.         current_audio->name = bootstrap[i]->name;
  306.     }
  307.     return(0);
  308. }
  309.  
  310. char *SDL_AudioDriverName(char *namebuf, int maxlen)
  311. {
  312.     if ( current_audio != NULL ) {
  313.         strncpy(namebuf, current_audio->name, maxlen-1);
  314.         namebuf[maxlen-1] = '\0';
  315.         return(namebuf);
  316.     }
  317.     return(NULL);
  318. }
  319.  
  320. int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
  321. {
  322.     SDL_AudioDevice *audio;
  323.  
  324.     /* Start up the audio driver, if necessary */
  325.     if ( ! current_audio ) {
  326.         if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
  327.              (current_audio == NULL) ) {
  328.             return(-1);
  329.         }
  330.     }
  331.     audio = current_audio;
  332.  
  333.     /* Verify some parameters */
  334.     if ( desired->callback == NULL ) {
  335.         SDL_SetError("SDL_OpenAudio() passed a NULL callback");
  336.         return(-1);
  337.     }
  338.     switch ( desired->channels ) {
  339.         case 1:    /* Mono */
  340.         case 2:    /* Stereo */
  341.         break;
  342.         default:
  343.         SDL_SetError("1 (mono) and 2 (stereo) channels supported");
  344.         return(-1);
  345.     }
  346.  
  347. #ifdef macintosh
  348.     /* FIXME: Need to implement PPC interrupt asm for SDL_LockAudio() */
  349. #else
  350.     /* Create a semaphore for locking the sound buffers */
  351.     audio->mixer_lock = SDL_CreateMutex();
  352.     if ( audio->mixer_lock == NULL ) {
  353.         SDL_SetError("Couldn't create mixer lock");
  354.         SDL_CloseAudio();
  355.         return(-1);
  356.     }
  357. #endif
  358.  
  359.     /* Calculate the silence and size of the audio specification */
  360.     SDL_CalculateAudioSpec(desired);
  361.  
  362.     /* Open the audio subsystem */
  363.     memcpy(&audio->spec, desired, sizeof(audio->spec));
  364.     audio->convert.needed = 0;
  365.     audio->enabled = 1;
  366.     audio->paused  = 1;
  367.  
  368. #ifndef ENABLE_AHI
  369.  
  370. /* AmigaOS opens audio inside the main loop */
  371.     audio->opened = audio->OpenAudio(audio, &audio->spec)+1;
  372.  
  373.     if ( ! audio->opened ) {
  374.         SDL_CloseAudio();
  375.         return(-1);
  376.     }
  377. #else
  378.     D(bug("Locking semaphore..."));
  379.     SDL_mutexP(audio->mixer_lock);
  380.  
  381.     audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
  382.     D(bug("Created thread...\n"));
  383.  
  384.     if ( audio->thread == NULL ) {
  385.         SDL_mutexV(audio->mixer_lock);
  386.         SDL_CloseAudio();
  387.         SDL_SetError("Couldn't create audio thread");
  388.         return(-1);
  389.     }
  390.  
  391.     while(!audio_configured)
  392.         SDL_Delay(100);
  393. #endif
  394.  
  395.     /* If the audio driver changes the buffer size, accept it */
  396.     if ( audio->spec.samples != desired->samples ) {
  397.         desired->samples = audio->spec.samples;
  398.         SDL_CalculateAudioSpec(desired);
  399.     }
  400.  
  401.     /* Allocate a fake audio memory buffer */
  402.     audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
  403.     if ( audio->fake_stream == NULL ) {
  404.         SDL_CloseAudio();
  405.         SDL_OutOfMemory();
  406.         return(-1);
  407.     }
  408.  
  409.     /* See if we need to do any conversion */
  410.     if ( memcmp(desired, &audio->spec, sizeof(audio->spec)) == 0 ) {
  411.         /* Just copy over the desired audio specification */
  412.         if ( obtained != NULL ) {
  413.             memcpy(obtained, &audio->spec, sizeof(audio->spec));
  414.         }
  415.     } else {
  416.         /* Copy over the audio specification if possible */
  417.         if ( obtained != NULL ) {
  418.             memcpy(obtained, &audio->spec, sizeof(audio->spec));
  419.         } else {
  420.             /* Build an audio conversion block */
  421.             if ( SDL_BuildAudioCVT(&audio->convert,
  422.                 desired->format, desired->channels,
  423.                         desired->freq,
  424.                 audio->spec.format, audio->spec.channels,
  425.                         audio->spec.freq) < 0 ) {
  426.                 SDL_CloseAudio();
  427.                 return(-1);
  428.             }
  429.             if ( audio->convert.needed ) {
  430.                 audio->convert.len = desired->size;
  431.                 audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
  432.                    audio->convert.len*audio->convert.len_mult);
  433.                 if ( audio->convert.buf == NULL ) {
  434.                     SDL_CloseAudio();
  435.                     SDL_OutOfMemory();
  436.                     return(-1);
  437.                 }
  438.             }
  439.         }
  440.     }
  441.  
  442. #ifndef ENABLE_AHI
  443.     /* Start the audio thread if necessary */
  444.     switch (audio->opened) {
  445.         case  1:
  446.             /* Start the audio thread */
  447.             audio->thread = SDL_CreateThread(SDL_RunAudio, audio);
  448.             if ( audio->thread == NULL ) {
  449.                 SDL_CloseAudio();
  450.                 SDL_SetError("Couldn't create audio thread");
  451.                 return(-1);
  452.             }
  453.             break;
  454.  
  455.         default:
  456.             /* The audio is now playing */
  457.             break;
  458.     }
  459. #else
  460.     SDL_mutexV(audio->mixer_lock);
  461.     D(bug("SDL_OpenAudio USCITA...\n"));
  462.  
  463. #endif
  464.  
  465.     return(0);
  466. }
  467.  
  468. SDL_audiostatus SDL_GetAudioStatus(void)
  469. {
  470.     SDL_AudioDevice *audio = current_audio;
  471.     SDL_audiostatus status;
  472.  
  473.     status = SDL_AUDIO_STOPPED;
  474.     if ( audio && audio->enabled ) {
  475.         if ( audio->paused ) {
  476.             status = SDL_AUDIO_PAUSED;
  477.         } else {
  478.             status = SDL_AUDIO_PLAYING;
  479.         }
  480.     }
  481.     return(status);
  482. }
  483.  
  484. void SDL_PauseAudio (int pause_on)
  485. {
  486.     SDL_AudioDevice *audio = current_audio;
  487.  
  488.     if ( audio ) {
  489.         audio->paused = pause_on;
  490.     }
  491. }
  492.  
  493. void SDL_LockAudio (void)
  494. {
  495.     SDL_AudioDevice *audio = current_audio;
  496.  
  497.     /* Obtain a lock on the mixing buffers */
  498.     if ( audio ) {
  499.         if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
  500.             return;
  501.         }
  502.         SDL_mutexP(audio->mixer_lock);
  503.     }
  504. }
  505.  
  506. void SDL_UnlockAudio (void)
  507. {
  508.     SDL_AudioDevice *audio = current_audio;
  509.  
  510.     /* Release lock on the mixing buffers */
  511.     if ( audio ) {
  512.         if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
  513.             return;
  514.         }
  515.         SDL_mutexV(audio->mixer_lock);
  516.     }
  517. }
  518.  
  519. void SDL_CloseAudio (void)
  520. {
  521.     SDL_QuitSubSystem(SDL_INIT_AUDIO);
  522. }
  523.  
  524. void SDL_AudioQuit(void)
  525. {
  526.     SDL_AudioDevice *audio = current_audio;
  527.  
  528.     if ( audio ) {
  529.         audio->enabled = 0;
  530.         if ( audio->thread != NULL ) {
  531.             SDL_WaitThread(audio->thread, NULL);
  532.         }
  533.         if ( audio->mixer_lock != NULL ) {
  534.             SDL_DestroyMutex(audio->mixer_lock);
  535.         }
  536.         if ( audio->fake_stream != NULL ) {
  537.             SDL_FreeAudioMem(audio->fake_stream);
  538.         }
  539.         if ( audio->convert.needed ) {
  540.             SDL_FreeAudioMem(audio->convert.buf);
  541.  
  542.         }
  543. #ifndef ENABLE_AHI
  544.         if ( audio->opened ) {
  545.             audio->CloseAudio(audio);
  546.             audio->opened = 0;
  547.         }
  548. #endif
  549.         /* Free the driver data */
  550.         audio->free(audio);
  551.         current_audio = NULL;
  552.     }
  553. }
  554.  
  555. #define NUM_FORMATS    6
  556. static int format_idx;
  557. static int format_idx_sub;
  558. static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
  559.  { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
  560.  { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
  561.  { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
  562.  { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
  563.  { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
  564.  { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
  565. };
  566.  
  567. Uint16 SDL_FirstAudioFormat(Uint16 format)
  568. {
  569.     for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
  570.         if ( format_list[format_idx][0] == format ) {
  571.             break;
  572.         }
  573.     }
  574.     format_idx_sub = 0;
  575.     return(SDL_NextAudioFormat());
  576. }
  577.  
  578. Uint16 SDL_NextAudioFormat(void)
  579. {
  580.     if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
  581.         return(0);
  582.     }
  583.     return(format_list[format_idx][format_idx_sub++]);
  584. }
  585.  
  586. void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
  587. {
  588.     switch (spec->format) {
  589.         case AUDIO_U8:
  590.             spec->silence = 0x80;
  591.             break;
  592.         default:
  593.             spec->silence = 0x00;
  594.             break;
  595.     }
  596.     spec->size = (spec->format&0xFF)/8;
  597.     spec->size *= spec->channels;
  598.     spec->size *= spec->samples;
  599. }
  600.